package com.only4play.configuration.resttemplate;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
* 优雅的http请求方式RestTemplate
* @Return:
*/

@Deprecated(since = "暂时启用")
@Slf4j
public class RestTemplateConfig {


    //==============Resttemplate相关参数====================
    @Value("${spring.restTemplate.readTimeout:5000}")
    private int readTimeout;
    @Value("${spring.restTemplate.connectTimeout:2000}")
    private int connectTimeout;

    /**
     * 配置RestTemplate
     *
     * @param clientHttpRequestFactory clientHttpRequestFactory
     * @return restTemplate
     */
    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
        RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
        //默认使用ISO-8859-1编码，此处修改为UTF-8
        List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
        for (HttpMessageConverter<?> converter : messageConverters) {
            if (converter instanceof StringHttpMessageConverter) {
                ((StringHttpMessageConverter) converter).setDefaultCharset(StandardCharsets.UTF_8);
            }
        }
        //设置自定义异常处理
        restTemplate.setErrorHandler(new LoggingErrorHandler());
        //设置日志拦截器
        restTemplate.getInterceptors().add(new LoggingInterceptor());
        return restTemplate;
    }

    @Bean
    public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setConnectTimeout(connectTimeout);//ms
        return factory;
    }

    /**
     * 自定义异常处理
     */
    private static class LoggingErrorHandler implements ResponseErrorHandler {

        @Override
        public boolean hasError(ClientHttpResponse response) throws IOException {
            return !response.getStatusCode().is2xxSuccessful();
        }

        @Override
        public void handleError(ClientHttpResponse response) throws IOException {
            //响应状态码错误时不抛出异常
        }
    }

    /**
     * 日志拦截器
     */
    private static class LoggingInterceptor implements ClientHttpRequestInterceptor {

        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
            traceRequest(request, body);
            long start = System.currentTimeMillis();
            ClientHttpResponse response = execution.execute(request, body);
            long end = System.currentTimeMillis();
            traceResponse(body, request, response, (end - start) / 1000.0f);
            return response;
        }

        private void traceRequest(HttpRequest request, byte[] body) {
            String logInfo = "\n===========================request begin===========================\n" +
                "URI         : " + request.getURI() + "\n" +
                "Method      : " + request.getMethod() + "\n" +
                "Headers     : " + request.getHeaders() + "\n" +
                "Request body: " + new String(body, StandardCharsets.UTF_8) + "\n" +
                "===========================request end==============================";
            log.debug(logInfo);
        }

        private void traceResponse(byte[] body, HttpRequest request, ClientHttpResponse response, float time) throws IOException {
            StringBuilder inputStringBuilder = new StringBuilder();
            try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), "UTF-8"))) {
                String line = bufferedReader.readLine();
                while (line != null) {
                    inputStringBuilder.append(line);
                    line = bufferedReader.readLine();
                }
            }
            StringBuilder logInfo = new StringBuilder();
            if (response.getStatusCode().is2xxSuccessful()) {
                logInfo.append("\n===========================response begin===========================\n")
                        .append("TIME         : ").append(time).append("s").append("\n")
                        .append("URI          : ").append(request.getURI()).append("\n")
                        .append("Method       : ").append(request.getMethod()).append("\n")
                        .append("Status code  : ").append(response.getStatusCode()).append("\n")
                        .append("Headers      : ").append(response.getHeaders()).append("\n")
                        .append("Response body: ").append(inputStringBuilder).append("\n")
                        .append("===========================response end==============================");
                log.debug(logInfo.toString());
            } else {
                logInfo.append("\n===========================response begin===========================\n")
                        .append("TIME         : ").append(time).append("s").append("\n")
                        .append("URI          : ").append(request.getURI()).append("\n")
                        .append("Method       : ").append(request.getMethod()).append("\n")
                        .append("Headers      : ").append(request.getHeaders()).append("\n")
                        .append("Request body : ").append(new String(body, StandardCharsets.UTF_8)).append("\n")
                        .append("Status code  : ").append(response.getStatusCode()).append("\n")
                        .append("Headers      : ").append(response.getHeaders()).append("\n")
                        .append("Response body: ").append(inputStringBuilder).append("\n")
                        .append("===========================response end==============================");
                log.error(logInfo.toString());
            }
        }


        private String getLogRules() {
            String rule = "";
            String path = System.getProperty("user.dir");
            StringBuffer sb = new StringBuffer();
            String logRulesPath = sb.append(path)
                    .append(File.separator)
                    .append("config")
                    .append(File.separator)
                    .append("log-rules")
                    .append(File.separator).append("log-print-rules.json").toString();
            FileInputStream fileInputStream = null;
            try {
                fileInputStream = new FileInputStream(logRulesPath);
                rule = IOUtils.toString(fileInputStream, StandardCharsets.UTF_8);
            } catch (IOException e) {
                log.error("Load rules file error.", e);
            } finally {
                if (fileInputStream != null) {
                    try {
                        fileInputStream.close();
                    } catch (IOException e) {
                        log.error("Closing stream error.", e);
                    }
                }
            }
            return rule;
        }

    }
}
